Skip to content

fix(runtime-host): recover legacy Root source messages - #3923

Merged
Astro-Han merged 8 commits into
apache:mainfrom
Sun-GLiang:fix/3902-legacy-message-recovery
Aug 29, 2026
Merged

fix(runtime-host): recover legacy Root source messages#3923
Astro-Han merged 8 commits into
apache:mainfrom
Sun-GLiang:fix/3902-legacy-message-recovery

Conversation

@Sun-GLiang

Copy link
Copy Markdown
Contributor

Summary

  • add an optional, shared proven-Root handoff contract for legacy source messages without message_admissions
  • atomically materialize legacy transcript entries while preserving admission authority, cancellation checks, conflict rejection, and idempotency
  • require exact Session/Turn/Run/Message Root receipt proof before Runtime Host recovery forwards fallback data
  • cover legacy follow-up, steering, repeated startup, and missing-proof fail-closed recovery

Root cause

#3721 made message-admission proof mandatory during handoff. Older terminal Root admissions can still own source messages but have no corresponding message_admissions row, so startup recovery failed with Message admission does not exist before the Host became ready.

Verification

  • npm --workspace @maka/storage run test: 970 passed, 16 skipped
  • Runtime Host full suite with --test-concurrency=1: 1242 passed, 9 skipped
  • npm run rebuild: passed
  • npm run typecheck: passed
  • npm run lint: passed
  • npm run check:stale: passed

The default parallel Runtime Host invocation exposed an unrelated shared control-cache cleanup race (ENOTEMPTY / ENOENT) on two runs; the failing Host-kernel case passed in isolation, the serial full suite passed, and all #3902 recovery tests passed in every run.

A production Desktop/Host run against an adopted workspace copy reached ready and materialized both legacy messages exactly once with clean SQLite integrity. The real workspace was intentionally not started because one active durable Goal would auto-resume external work.

Closes #3902

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this head and found blocking issues.

[P1] Recovered legacy input appended out-of-order

Missing legacy source inserted at MAX+1 regardless of its original Turn/time; forms [old outputs..., recovered user input] and corrupts catalog preview with stale text + new timestamp.

Fix: recover in original Turn/time order or use non-linear compatible representation with regression for non-empty transcript.

[P1] Two legacy crash cuts still crash Host startup

Missing Root-source transcript with run===undefined or non-terminal Run still throws does not match queue source before nonterminal recovery can run — Host fails despite recoverable receipt.

Fix: allow proof-owned source to materialize fail-closed during later recovery; add crash-cut tests.

Hosted test/windows_recovery: SUCCESS, but code is NO-GO.

简体中文历史恢复时序与启动崩溃问题。

Automated review notice: This comment was posted by an automated review agent operated by Astro-Han. It is not an independent human review and does not replace one.

@Sun-GLiang

Copy link
Copy Markdown
Contributor Author

Implemented the review remediation in c073644.

Changes:

  • preserve append semantics for ordinary admission-backed handoffs; historical reordering is limited to receipt-proven Root sources
  • insert recovered Root sources before same-Turn output and newer/equal-time transcript rows while preserving chunk/payload foreign keys
  • reject fully materialized or partial source-order conflicts, steering Turn conflicts, and unsafe sequence ranges atomically
  • validate exact durable Root source receipts during recovery preparation, before creating or terminalizing a Run
  • cover terminal, missing-Run, nonterminal-Run, repeated recovery, equal timestamps, partial/all-existing conflicts, and overflow

Verification:

  • @maka/storage: 993 total, 977 passed, 16 skipped, 0 failed
  • @maka/runtime-host: 1255 total, 1246 passed, 9 skipped, 0 failed
  • npm run typecheck: passed
  • npm run lint: passed
  • npm run check:stale: passed

No design or plan documents are included. Please re-review the updated changes.

@Sun-GLiang

Copy link
Copy Markdown
Contributor Author

Fixed the CI formatting failure in e63367a. The change is formatting-only across the three files reported by Biome.

Fresh local verification:

  • npm run format:check: passed
  • npm run lint: passed
  • npm run typecheck: passed
  • npm run rebuild: passed
  • npm run check:stale: passed

@Sun-GLiang
Sun-GLiang force-pushed the fix/3902-legacy-message-recovery branch from e63367a to 8e2c6a6 Compare August 27, 2026 01:30
@Sun-GLiang

Copy link
Copy Markdown
Contributor Author

Rebased onto current main at 6762085 and resolved the conflicts with #3803 while preserving both authority changes: SubmittedTurnIntent support from main and receipt-proven legacy Root recovery from this PR.

Fresh post-rebase verification:

  • full rebuild: passed
  • typecheck: passed
  • storage: 1003 total, 987 passed, 16 skipped, 0 failed
  • runtime-host: 1284 total, 1275 passed, 9 skipped, 0 failed
  • lint: passed
  • format:check: passed
  • check:stale: passed

GitHub now reports the PR as MERGEABLE; remaining BLOCKED state is checks/review, not a merge conflict.

@github-actions github-actions Bot added the effort/XL Over 1000 readable lines label Aug 27, 2026
@Sun-GLiang
Sun-GLiang force-pushed the fix/3902-legacy-message-recovery branch from 8e2c6a6 to fb45385 Compare August 29, 2026 09:58
@Sun-GLiang

Copy link
Copy Markdown
Contributor Author

已解决与最新 main (b16376d78) 的冲突并完成 rebase,更新后的 head 为 fb453857b

冲突处理中同时保留了最新主线的 WorkHub delegation / Session admission 恢复语义,以及 #3902 对已验证 legacy Root source 的严格兼容恢复;steering 继续使用其独立持久化证明,未放宽普通消息的权威校验。

本地验证:

  • npm run rebuild
  • npm run typecheck
  • npm --workspace @maka/storage run test ✅(1028 tests,0 fail,16 skipped)
  • npm --workspace @maka/runtime-host run test ✅(1372 tests,0 fail,9 skipped)
  • npm run lint
  • npm run format:check
  • npm run check:stale
  • git diff --check

GitHub 当前报告 MERGEABLE;新一轮 CI 已排队运行。

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for carefully working through the legacy Root-source recovery edge cases.

I reviewed exact head fb453857b4240e11dd90afa1caa04ffce2a05140. The problem is real: legacy persisted Root messages can lack a source while still needing a trustworthy origin during handoff. This implementation keeps the proof chain fail-closed, performs the repair inside the existing transaction, and closes the earlier correctness gaps without introducing another durable authority. I found no P0 or P1 issue, so I’m approving.

One non-blocking P2 for future hardening: ordinary Root handoffs can now cause readSessionMessageOrderingSync() to read and decode the full Session transcript inside the write transaction. Repeating that on very long Sessions may approach quadratic work and hold the write lock longer than necessary. It would be worth narrowing the scan to missing legacy candidates or affected ordering boundaries, or adding a long-history regression/performance case. This does not affect the correctness of the current fix and does not block approval.

Review analysis was assisted by Codex and independent @reviewer agents; Astro-Han verified the exact-head code paths, reachability, and CI state and owns this review.

中文对照

感谢你认真处理这些旧版 Root 来源恢复的边界情况。

我审查了当前提交 fb453857b4240e11dd90afa1caa04ffce2a05140。这个问题是真实存在的:旧版持久化的 Root 消息可能缺少 source,但在 handoff 时仍然需要一个可信的来源。当前实现保持了严格失败的证明链,在现有事务内完成修复,也关闭了此前的正确性缺口,没有引入新的持久化权威来源。我没有发现 P0 或 P1,因此 Approve。

有一个不阻塞的 P2,供后续收敛:普通 Root handoff 现在可能让 readSessionMessageOrderingSync() 在写事务中读取并解码整个 Session transcript。对于很长的 Session,重复执行可能接近二次复杂度,并延长写锁持有时间。后续可以考虑只扫描缺少来源的旧记录或受影响的排序边界,或者补一个长历史的回归/性能用例。这不影响当前修复的正确性,也不阻塞本次 Approve。

本次分析由 Codex 和独立的 @reviewer agents 协助;Astro-Han 核验了当前提交的代码路径、可达性和 CI 状态,并对本次评审负责。

@Sun-GLiang

Copy link
Copy Markdown
Contributor Author

已处理 review 中的 P2(commit 6f730a5af)。

根因是普通 Root handoff 虽有现存 message admission,也会携带 Root proof;存储层此前仅凭 proof 存在就进入 legacy 排序恢复,从而读取并解码整个 Session transcript。

整改后:

  • 只有 admission 缺失、实际需要 Root fallback 的消息才标记为 legacy 候选并进入 transcript 排序扫描;
  • admission 存在时仍校验 proof 内容一致性,但保持原有尾部追加路径,不扫描完整 transcript;
  • admission 缺失的 legacy 恢复、顺序冲突、幂等和失败关闭行为保持不变;
  • 新增回归测试,覆盖“普通 admission + Root proof + 已有输出”仍按普通追加语义处理。该测试在修复前按预期失败,修复后通过。

验证:

  • SQLite store 测试文件:72/72 pass
  • @maka/storage:1028 tests,0 fail(16 skipped)
  • @maka/runtime-host:1372 tests,0 fail(9 skipped)
  • typecheck / lint / format / stale / diff check:通过。

@Astro-Han
Astro-Han merged commit 6b75a72 into apache:main Aug 29, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/XL Over 1000 readable lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(runtime-host): legacy source messages block Desktop startup after upgrade

2 participants